const UNI_STORAGE_KEYS = 'uni-storage-keys';
Array.prototype.remove = function (val) {
    const index = this.indexOf(val);
    if (index > -1) {
        this.splice(index, 1);
    }
};

export class MyStorage {
    constructor () {
        const vm = this;
    }

    // 存储
    set (key, value) {
        try {
            const data = uni.setStorageSync(key, value);
            return data;
        } catch (e) {
            return new Promise(resolve => {
                uni.setStorage({
                    key,
                    data: value,
                    complete () {
                        resolve(...arguments)
                    }
                });
            })
        }
    }

    // 读取
    get (key) {
        try {
            return uni.getStorageSync(key);
        } catch (e) {
            return new Promise(resolve => {
                uni.getStorage({
                    key,
                    complete () {
                        resolve(...arguments)
                    }
                });
            })
        }
    }

    // 清除
    remove (key) {
        try {
            uni.removeStorageSync(key);
        } catch (e) {
            uni.removeStorage({
                key,
                success: function (res) {
                    uni.showToast({title: '清除缓存成功'})
                }
            });
        }
    }

    // 清除对象
    clear () {
        try {
            uni.clearStorageSync();
        } catch (e) {
            uni.clearStorage();
        }
    }
}

export const MyLStorage = new MyStorage();

const util = {
    dateFormat: function (date, fmt = 'YYYY-MM-DD HH:mm:ss') {
        if (!date) {
            return ''
        }
        if (typeof date === 'string') {
            date = new Date(date.replace(/-/g, '/'))
        }
        if (typeof date === 'number') {
            date = new Date(date)
        }
        let o = {
            'M+': date.getMonth() + 1,
            'D+': date.getDate(),
            'h+': date.getHours() % 12 === 0 ? 12 : date.getHours() % 12,
            'H+': date.getHours(),
            'm+': date.getMinutes(),
            's+': date.getSeconds(),
            'q+': Math.floor((date.getMonth() + 3) / 3),
            'S': date.getMilliseconds()
        }
        let week = {
            '0': '\u65e5',
            '1': '\u4e00',
            '2': '\u4e8c',
            '3': '\u4e09',
            '4': '\u56db',
            '5': '\u4e94',
            '6': '\u516d'
        }
        if (/(Y+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, (date.getFullYear() + '').substr(4 - RegExp.$1.length))
        }
        if (/(E+)/.test(fmt)) {
            fmt = fmt.replace(RegExp.$1, ((RegExp.$1.length > 1) ? (RegExp.$1.length > 2 ? '\u661f\u671f' : '\u5468') : '') + week[date.getDay() + ''])
        }
        for (let k in o) {
            if (new RegExp('(' + k + ')').test(fmt)) {
                fmt = fmt.replace(RegExp.$1, (RegExp.$1.length === 1) ? (o[k]) : (('00' + o[k]).substr(('' + o[k]).length)))
            }
        }
        return fmt
    },
    setExpireDate: function (expire, date = new Date()) {
        switch (!!date) {
            case typeof date === 'number' || (typeof date === 'string' && /^[1-2][0-9][0-9][0-9](-|\/)[0-1]{0,1}[0-9](-|\/)[0-3]{0,1}[0-9]/.test(date)):
                date = new Date(typeof date === 'string' ? date.replace(/-/g, '/') : date)
                break
            case date.constructor !== Date:
                date = new Date()
                break
        }

        let unitArr = ['s', 'm', 'h', 'd', 'M', 'y']
        let re = new RegExp(unitArr.join('|'))
        if (typeof expire !== 'string') return 0

        if (re.test(expire)) {
            unitArr.forEach(value => {
                const reg = new RegExp(`\\d+${value}`, 'g')
                if (!reg.test(expire)) return
                expire.replace(reg, function (expire) {
                    let unit = expire.replace(/\d/g, '')
                    let num = +expire.replace(/[^0-9]/g, '')
                    let fIndex = unitArr.indexOf(unit)
                    if (fIndex === -1) return
                    switch (fIndex) {
                        case 0://秒
                            date.setSeconds(date.getSeconds() + num)
                            break
                        case 1://分
                            date.setMinutes(date.getMinutes() + num)
                            break
                        case 2://时
                            date.setHours(date.getHours() + num)
                            break
                        case 3://日
                            date.setDate(date.getDate() + num)
                            break
                        case 4://月
                            date.setMonth(date.getMonth() + num)
                            break
                        case 5://年
                            date.setFullYear(date.getFullYear() + num)
                            break
                    }
                    date = new Date(date)
                })
            })
        } else if (/-|\/|\:/g.test(expire)) {
            let dateArr = expire.split(/\s+/g)
            let time = dateArr[1] || ''
            let dateStr = dateArr[0] || ''
            if (dateArr.length > 0 && /\:/g.test(dateArr[0])) {
                time = dateArr[0]
                dateStr = ''
            }
            let Time = time.split(':').reverse()
            let DateStr = dateStr.split(/\/|\-/).reverse()
            let DateArr = [Time[0], Time[1], Time[2], DateStr[0], DateStr[1], DateStr[2]]
            DateArr.forEach((value, index, array) => {
                const num = isNaN(+value) ? 0 : +value
                switch (index) {
                    case 0://秒
                        date.setSeconds(date.getSeconds() + num)
                        break
                    case 1://分
                        date.setMinutes(date.getMinutes() + num)
                        break
                    case 2://时
                        date.setHours(date.getHours() + num)
                        break
                    case 3://日
                        date.setDate(date.getDate() + num)
                        break
                    case 4://月
                        date.setMonth(date.getMonth() + num)
                        break
                    case 5://年
                        date.setFullYear(date.getFullYear() + num)
                        break
                }
                date = new Date(date)
            })
        }
        return +date
    },
    dateMax: function (target, date = new Date()) {
        switch (!!date) {
            case typeof date === 'number' || (typeof date === 'string' && /^[1-2][0-9][0-9][0-9](-|\/)[0-1]{0,1}[0-9](-|\/)[0-3]{0,1}[0-9]/.test(date)):
                date = new Date(typeof date === 'string' ? date.replace(/-/g, '/') : date)
                break
            case date.constructor !== Date:
                date = new Date()
                break
        }
        if (typeof target === 'number' || (typeof target === 'string' && /^[1-2][0-9][0-9][0-9](-|\/)[0-1]{0,1}[0-9](-|\/)[0-3]{0,1}[0-9]/.test(target))) {
            target = new Date(typeof date === 'string' ? date.replace(/-/g, '/') : target)
        }
        if (!target || target.constructor !== Date) return 0
        return Math.max(+target, +date) === +target ? 1 : 2
    },
    getStorageInfoSync () {
        try {
            const res = uni.getStorageInfoSync();
            return Promise.resolve(res)
        } catch (e) {
            // error
            return new Promise(resolve => {
                uni.getStorageInfo({
                    complete (res) {
                        resolve(res)
                    }
                })
            })
        }
    },
    async getNewStorageArr () {
        const StorageInfo = await util.getStorageInfoSync();
        let newStorageArr = StorageInfo.keys ? StorageInfo.keys : [];
        if (newStorageArr) {
            try {
                if (typeof newStorageArr === "string") {
                    newStorageArr = JSON.parse(newStorageArr);
                }
                if (!Array.isArray(newStorageArr)) newStorageArr = [];
            } catch (e) {
                newStorageArr = [];
            }
        } else newStorageArr = [];
        return Promise.resolve(newStorageArr);
    },
    getStorage: () => MyLStorage,
    unique (arr) {
        const res = new Map();
        return arr.filter((a) => !res.has(a) && res.set(a, 1))
    }
}

export const Storage = {
    setStorageSync (key, data, expire_date) {
        if (typeof key !== 'string') return
        const e = expire_date ? util.setExpireDate(expire_date, undefined) : null;
        MyLStorage.set(key, {
            data,
            expire_date: e,
            expire_str: util.dateFormat(e),
            update_time: util.dateFormat(new Date())
        })
    },
    getStorageSync (key) {
        if (typeof key !== 'string') return;
        const Storage = MyLStorage.get(key);
        if (!Storage) return null;
        if (util.dateMax(Storage.expire_date) === 2) return this.removeStorageSync(...arguments);
        return Storage.data
    },
    removeStorageSync (key) {
        if (typeof key !== 'string') return Promise.reject();
        return MyLStorage.remove(key)
    },
    async clearStorageSync (reg) {
        if (!reg) return MyLStorage.clear();
        if (typeof reg !== 'string' && reg.constructor !== RegExp) return;
        if (typeof reg !== 'string') reg = new RegExp(reg);
        const newStorageArr = await util.getNewStorageArr();
        for (const val of newStorageArr) {
            if (reg.test(val)) this.removeStorageSync(val)
        }
    },
    async clearExpiredStorageSync () {
        const newStorageArr = await util.getNewStorageArr();
        for (const val of newStorageArr) {
            this.getStorageSync(val)
        }
    },
    /**
     * 清除指定前缀的本地存储
     * @param key 前缀  指示3个字符串以上
     * @returns {Promise<void>}
     */
    async clearInterimStorageSync (key = "interim-") {
        if (typeof key !== "string" || key.length < 4) return;
        const reg = new RegExp(`^(${key})`)
        const newStorageArr = await util.getNewStorageArr();
        for (const val of newStorageArr) {
            if (reg.test(val)) this.removeStorageSync(val);
        }
    },
}
